package cz.data.domain.masterdata.service.impl;

import cz.data.domain.metadata.model.entity.MetadataSourceEntity;
import cz.data.domain.metadata.rpc.MetadataSourceFeign;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cz.data.common.mybatis.BaseServiceImpl;
import cz.data.common.core.DataConstant;
import cz.data.domain.masterdata.dao.ModelColumnDao;
import cz.data.domain.masterdata.dao.ModelDao;
import cz.data.domain.masterdata.mapstruct.ModelMapstruct;
import cz.data.domain.masterdata.model.dto.ModelDto;
import cz.data.domain.masterdata.model.entity.ModelColumnEntity;
import cz.data.domain.masterdata.model.entity.ModelEntity;
import cz.data.domain.masterdata.service.ModelService;
import cz.data.domain.standard.model.entity.DictEntity;
import cz.data.domain.standard.rpc.StandardDictFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 主数据模型表 服务实现类
 * </p>
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class ModelServiceImpl extends BaseServiceImpl<ModelDao, ModelEntity> implements ModelService {

    @Autowired
    private ModelDao modelDao;

    @Autowired
    private ModelMapstruct modelMapstruct;

    @Autowired
    private ModelColumnDao modelColumnDao;

    @Autowired
    StandardDictFeign standardDictFeign;
    @Resource
    MetadataSourceFeign metadataSourceFeign;

    private static final String BIND_GB_CODE = "gb_code";
    private static final String BIND_GB_NAME = "gb_name";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ModelEntity saveModel(ModelDto modelDto) {
        ModelEntity model = modelMapstruct.toEntity(modelDto);
        model.setFlowStatus(DataConstant.AuditState.AGREE.getKey());
        model.setIsSync(DataConstant.TrueOrFalse.FALSE.getKey());
        if (StringUtils.isBlank(model.getModelPhysicalTable())) {
            String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            model.setModelPhysicalTable("dynamic_" + format);
        }
        modelDao.insert(model);
        String modelId = model.getId();
        MetadataSourceEntity source = metadataSourceFeign.getMetadataSourceById(model.getSourceId());
        List<ModelColumnEntity> modelColumns = model.getModelColumns();
        if (CollectionUtils.isNotEmpty(modelColumns)) {
            for (ModelColumnEntity column : modelColumns) {
                column.setModelId(modelId);
                modelColumnDao.insert(column);
            }
        }
        return model;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ModelEntity updateModel(ModelDto modelDto) {
        ModelEntity model = modelMapstruct.toEntity(modelDto);
        modelDao.updateById(model);
        String modelId = model.getId();
        modelColumnDao.delete(Wrappers.<ModelColumnEntity>lambdaQuery()
                .eq(ModelColumnEntity::getModelId, modelId));
        List<ModelColumnEntity> modelColumns = model.getModelColumns();
        if (CollectionUtils.isNotEmpty(modelColumns)) {
            for (ModelColumnEntity column : modelColumns) {
                column.setModelId(modelId);
                modelColumnDao.insert(column);
            }
        }
        return model;
    }

    @Override
    public ModelEntity getModelById(String id) {
        return super.getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteModelById(String id) {
        modelColumnDao.delete(Wrappers.<ModelColumnEntity>lambdaQuery()
                .eq(ModelColumnEntity::getModelId, id));
        modelDao.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteModelBatch(List<String> ids) {
        modelColumnDao.delete(Wrappers.<ModelColumnEntity>lambdaQuery()
                .in(ModelColumnEntity::getModelId, ids));
        modelDao.deleteBatchIds(ids);
    }

    @Override
    public Map<String, Object> getTableParamById(String id) {
        ModelEntity modelEntity = super.getById(id);
        String tableName = modelEntity.getModelPhysicalTable();
        List<ModelColumnEntity> modelColumns = modelEntity.getModelColumns();
        // 列表展示字段
        List<Map<String, Object>> columnList = modelColumns.stream().filter(s -> DataConstant.TrueOrFalse.TRUE.getKey().equals(s.getIsList())).map(s -> {
            Map<String, Object> map = new HashMap<>(4);
            map.put("prop", s.getColumnName());
            map.put("label", s.getColumnComment());
            return map;
        }).collect(Collectors.toList());
        // 查询参数字段
        List<Map<String, Object>> queryList = modelColumns.stream().filter(s -> DataConstant.TrueOrFalse.TRUE.getKey().equals(s.getIsQuery())).map(s -> {
            Map<String, Object> map = new HashMap<>(4);
            map.put("column", s.getColumnName());
            map.put("columnName", s.getColumnComment());
            map.put("columnType", s.getColumnType());
            map.put("columnScale", s.getColumnScale());
            map.put("queryType", s.getQueryType());
            map.put("htmlType", s.getHtmlType());
            if (DataConstant.TrueOrFalse.TRUE.getKey().equals(s.getIsBindDict()) && StringUtils.isNotBlank(s.getBindDictTypeId())) {
                String bindDictColumn = s.getBindDictColumn();
                List<DictEntity> dictList = standardDictFeign.getDictEntityByDictTypeId(s.getBindDictTypeId());
                List<Map<String, Object>> mapList = dictList.stream().map(d -> {
                    Map<String, Object> dictMap = new HashMap<>(4);
                    dictMap.put("id", d.getId());
                    dictMap.put("value", BIND_GB_CODE.equals(bindDictColumn) ? d.getGbCode() : d.getGbName());
                    dictMap.put("label", d.getGbName());
                    return dictMap;
                }).collect(Collectors.toList());
                map.put("dictList", mapList);
            }
            return map;
        }).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>(4);
        map.put("modelId", id);
        map.put("tableName", tableName);
        map.put("columnList", columnList);
        map.put("queryList", queryList);
        return map;
    }

    @Override
    public Map<String, Object> getFormParamById(String id) {
        ModelEntity modelEntity = super.getById(id);
        String tableName = modelEntity.getModelPhysicalTable();
        List<ModelColumnEntity> modelColumns = modelEntity.getModelColumns();
        List<Map<String, Object>> columnList = modelColumns.stream()
                .filter(s -> DataConstant.TrueOrFalse.FALSE.getKey().equals(s.getIsSystem()))
                .map(s -> {
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("id", s.getId());
                    map.put("columnName", s.getColumnName());
                    map.put("columnComment", s.getColumnComment());
                    map.put("columnType", s.getColumnType());
                    map.put("columnLength", s.getColumnLength());
                    map.put("columnScale", s.getColumnScale());
                    map.put("defaultValue", s.getDefaultValue());
                    map.put("isRequired", s.getIsRequired());
                    map.put("isInsert", s.getIsInsert());
                    map.put("isEdit", s.getIsEdit());
                    map.put("isDetail", s.getIsEdit());
                    map.put("isList", s.getIsList());
                    map.put("isQuery", s.getIsQuery());
                    map.put("queryType", s.getQueryType());
                    map.put("isBindDict", s.getIsBindDict());
                    if (DataConstant.TrueOrFalse.TRUE.getKey().equals(s.getIsBindDict()) && StringUtils.isNotBlank(s.getBindDictTypeId())) {
                        String bindDictColumn = s.getBindDictColumn();
                        List<DictEntity> dictList = standardDictFeign.getDictEntityByDictTypeId(s.getBindDictTypeId());
                        List<Map<String, Object>> mapList = dictList.stream().map(d -> {
                            Map<String, Object> dictMap = new HashMap<>(4);
                            dictMap.put("id", d.getId());
                            dictMap.put("value", BIND_GB_CODE.equals(bindDictColumn) ? d.getGbCode() : d.getGbName());
                            dictMap.put("label", d.getGbName());
                            return dictMap;
                        }).collect(Collectors.toList());
                        map.put("dictList", mapList);
                    }
                    map.put("htmlType", s.getHtmlType());
                    return map;
                }).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>(4);
        map.put("modelId", id);
        map.put("tableName", tableName);
        map.put("columnList", columnList);
        return map;
    }

}
